﻿using System;
using System.Collections.Generic;
using Tools.Domain.Specifications.Constraints;
using Rhino.Mocks;
using Tools.Domain.Specifications;

namespace Webshop20.UnitTests.Builder
{
    class BuildConstraintSet<T>
    {
        private T fakeEntity;
        private IConstraintTarget<T> constraintTarget;
        IConstraintSet<T> constraintSet;
        private IConstraintContext constraintContext;

        public BuildConstraintSet()
        {
            constraintContext = MockRepository.GenerateMock<IConstraintContext>();
            constraintTarget = MockRepository.GenerateMock<IConstraintTarget<T>>(); //new ConstraintTargetFake();
            constraintSet = MockRepository.GenerateMock<IConstraintSet<T>>(); //repository.DynamicMultiMock<IConstraintSet<T>>(typeof(IConstraintTarget<T>));//typeof(IConstraintTarget<T>));
            constraintSet.Stub(x => x.ForMethod(y=> Nothing("T")))
                .Repeat.Any()
                .IgnoreArguments()
                .Return(constraintTarget);
            constraintSet.Stub(x => x.For(y => y.ToString()))
                .Repeat.Any()
                .IgnoreArguments()
                .Return(constraintTarget);
            constraintSet.Stub(x => x.ConstraintContext).Return(constraintContext);
        }

        public BuildConstraintSet<T> WithInvariantValidation(bool expectedValidationResult, T someEntityOfT)
        {
            constraintSet.Stub(x => x.InvarantsAreSatisfiedBy(someEntityOfT)).IgnoreArguments().Repeat.Any().Return(expectedValidationResult);
            return this;
        }

        private void Nothing(string input)
        {
            
        }

        public BuildConstraintSet<T> WithPreconditionValidation<S>(bool expectedValidationResult, S someEntityOfS)
        {
            //constraintTarget.precondtionReturnValue = expectedValidationResult;
            constraintTarget.Stub(x => x.PreconditionsAreSatisfiedBy(someEntityOfS)).IgnoreArguments().Repeat.Any().Return(expectedValidationResult);
            return this;
        }

        public BuildConstraintSet<T> WithPostConditionValidation<S>(bool expectedValidationResult, S someEntityOfS)
        {
            //constraintTarget.postconditionReturnValue = expectedValidationResult;
            (constraintTarget).Stub(x => x.PostconditionsAreSatisfiedBy(someEntityOfS)).IgnoreArguments().Repeat.Any().Return(expectedValidationResult);
            return this;
        }

        public BuildConstraintSet<T> WithInvariantErrors(IEnumerable<ISpecificationError> errors)
        {
            constraintSet.Stub(x => x.GetInvariantsSpecificationErrors()).Return(errors);
            return this;
        }

        public BuildConstraintSet<T> WithPreconditionErrors<S>(IList<ISpecificationError> errors)
        {
            //constraintTarget.preconditionErrors = errors;
            (constraintTarget).Stub(x => x.GetPreconditionSpecificationErrors<S>()).Return(errors);
            return this;
        }

        public BuildConstraintSet<T> WithPostconditionErrors<S>(IList<ISpecificationError> errors)
        {
            //constraintTarget.postcondtionErrors = errors;
            (constraintTarget).Stub(x => x.GetPostcondtionSpecificationErrors<S>()).Return(errors);
            return this;
        }

        public BuildConstraintSet<T> WithInvariantValidationSuccess(T dummy)
        {
            WithInvariantValidation(true, dummy);
            WithInvariantErrors(NewEmptySpecificationList());
            return this;
        }

        public BuildConstraintSet<T> WithPostconditionsValidationSuccess<S>(S dummy)
        {
            WithPostConditionValidation(true, dummy);
            WithPostconditionErrors<S>(NewEmptySpecificationList());
            return this;
        }

        public BuildConstraintSet<T> WithPreconditionValidationSuccess<S>(S dummy)
        {
            WithPreconditionValidation(true, dummy);
            WithPreconditionErrors<S>(NewEmptySpecificationList());
            return this;
        }

        public BuildConstraintSet<T> WithPreconditionValidationFailure<S>(S dummy)
        {
            WithPreconditionValidation(false, dummy);
            WithPreconditionErrors<S>(NewFilledSpecificationList());
            return this;
        }

        public BuildConstraintSet<T> WithInvariantValidationFailure(T dummy)
        {
            WithInvariantValidation(false, dummy);
            WithInvariantErrors(NewFilledSpecificationList());
            return this;
        }

        public List<ISpecificationError> NewFilledSpecificationList()
        {
            return new List<ISpecificationError>() {new SpecificationError(SpecificationType.Leaf, null)};
        }

        public List<ISpecificationError> NewEmptySpecificationList()
        {
            return new List<ISpecificationError>();
        }

        public IConstraintSet<T> Build()
        {
            //repository.ReplayAll();
            return 
                constraintSet;
        }

        public class ConstraintTargetFake : IConstraintTarget<T>
        {
            public bool postconditionReturnValue;
            public bool precondtionReturnValue;
            public IEnumerable<ISpecificationError> preconditionErrors;
            public IEnumerable<ISpecificationError> postcondtionErrors;

            public ConstraintTargetFake(bool precondtionReturnValue, bool postconditionReturnValue, IEnumerable<ISpecificationError> preconditionErrors, IEnumerable<ISpecificationError> postcondtionErrors)
            {
                this.precondtionReturnValue = precondtionReturnValue;
                this.postcondtionErrors = postcondtionErrors;
                this.preconditionErrors = preconditionErrors;
                this.postconditionReturnValue = postconditionReturnValue;
            }

            public ConstraintTargetFake()
            {
                this.precondtionReturnValue = true;
                this.postcondtionErrors = new List<ISpecificationError>();
                this.preconditionErrors = new List<ISpecificationError>();
                this.postconditionReturnValue = true;
            }

            #region IConstraintTarget<T> Members




            public IConstraintTarget<T> AddInvariant(ISpecification<T> specification)
            {
                throw new NotImplementedException();
            }

            public IConstraintTarget<T> AddPostcondition<S>(ISpecification<S> specification, IConstraintContext context)
            {
                throw new NotImplementedException();
            }

            public IConstraintTarget<T> AddPostcondition<S>(ISpecification<S> specification)
            {
                throw new NotImplementedException();
            }

            public IConstraintTarget<T> AddPrecondition<S>(ISpecification<S> specification, IConstraintContext context)
            {
                throw new NotImplementedException();
            }

            public IConstraintTarget<T> AddPrecondition<S>(ISpecification<S> specification)
            {
                throw new NotImplementedException();
            }

            public IEnumerable<ISpecificationError> GetPostcondtionSpecificationErrors<S>()
            {
                return postcondtionErrors;
            }

            public IEnumerable<ISpecificationError> GetPreconditionSpecificationErrors<S>()
            {
                return preconditionErrors;
            }

            public bool PostconditionsAreSatisfiedBy<S>(S entity, ref IList<ISpecificationError> errors)
            {
                return postconditionReturnValue;
            }

            public bool PostconditionsAreSatisfiedBy<S>(S entity)
            {
                return postconditionReturnValue;
            }

            public bool PreconditionsAreSatisfiedBy<S>(S entity, ref IList<ISpecificationError> errors)
            {
                return precondtionReturnValue;
            }

            public bool PreconditionsAreSatisfiedBy<S>(S entity)
            {
                return precondtionReturnValue;
            }

            #endregion
        }



    }
}